package services

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"

	"github.com/sirupsen/logrus"
)

type CommandPayload struct {
	Method string                 `json:"method"`
	Params map[string]interface{} `json:"params"`
}

// topic:devices/command/{mac}/{message_id}
func DealTpCommand(topic string, payload []byte) error {
	// 校验主题合法性获取mac地址
	mac, err := getMacFromTopic(topic)
	if err != nil {
		return err
	}
	logrus.Info("mac:", mac)

	// 解析payload
	p, err := ParseCommandPayload(payload)
	if err != nil {
		return err
	}
	// 发送命令给设备
	err = AssembleCommandPayload(mac, p.Method, p.Params)
	return err
}

// 从主题中解析出mac地址
func getMacFromTopic(topic string) (string, error) {
	topicList := strings.Split(topic, "/")
	if len(topicList) < 5 {
		return "", fmt.Errorf("topic:%s is invalid", topic)
	}
	// 验证devices/command/开头
	if topicList[2] != "devices" || topicList[3] != "command" {
		return "", fmt.Errorf("topic:%s is invalid", topic)
	}
	// MAC地址
	return topicList[4], nil
}

// 解析payload
func ParseCommandPayload(payload []byte) (*CommandPayload, error) {
	// payload转json
	var commandPayload CommandPayload
	err := json.Unmarshal(payload, &commandPayload)
	if err != nil {
		return nil, err
	}
	// logrus.Info("commandPayload:", commandPayload)
	return &commandPayload, nil
}

// 组装发给设备的命令报文
func AssembleCommandPayload(mac string, method string, params map[string]interface{}) error {
	switch method {
	case "DEVICE_CONTROL":
		// 设备控制命令
		return AssembleDeviceControlPayload(mac, method, params)
	case "SPK_CTRL_T1":
		// 喷淋控制器时间段1命令
		return AssembleSpkCtrlT1Payload(mac, method, params)
	case "SPK_CTRL_T2":
		// 喷淋控制器时间段2命令
		return AssembleSpkCtrlT2Payload(mac, method, params)
	case "LIGHT_CTRL_T":
		// 灯光控制器时间段命令
		return AssembleLightCtrlTPayload(mac, method, params)
	case "FAN_CTRL_T":
		// 风扇控制器时间段命令
		return AssembleFanCtrlTPayload(mac, method, params)
	case "MIST_CTRL_T":
		// 雾化控制器时间段命令
		return AssembleMistCtrlTPayload(mac, method, params)
	case "PUMP_CTRL_T":
		// 水泵控制器时间段命令
		return AssemblePumpCtrlTPayload(mac, method, params)
	default:
		return fmt.Errorf("method:%s is invalid", method)
	}
}

type ByteData struct {
	StartAddr int         `json:"startAddr"`
	Length    int         `json:"length"`
	Value     interface{} `json:"value"`
}

// 按照[]ByteData组装发送命令给设备
func AssembleCommandPayloadByByteData(mac string, method string, byteList []ByteData) error {
	// 按照startAddr排序
	byteList = quickSortByteData(byteList)
	logrus.Info("byteList:", byteList)
	// 切分连续的ByteData
	byteListSlice := splitByteData(byteList)
	logrus.Info("byteListSlice:", byteListSlice)

	// 组装命令报文
	for _, v := range byteListSlice {
		payload, err := assembleSendPayload(v)
		if err != nil {
			return err
		}
		//logrus.Info("payload:", payload)
		// 发送命令给设备
		err = SendDataToDevice(mac, payload)
		if err != nil {
			logrus.Warn("SendDataToDevice err:", err)
		}
	}
	return nil
}

// 快速排序，根据ByteData的StartAddr字段排序
func quickSortByteData(byteList []ByteData) []ByteData {
	if len(byteList) <= 1 {
		return byteList
	}
	mid := byteList[0]
	var left []ByteData
	var right []ByteData
	for i := 1; i < len(byteList); i++ {
		if byteList[i].StartAddr < mid.StartAddr {
			left = append(left, byteList[i])
		} else {
			right = append(right, byteList[i])
		}
	}
	left = quickSortByteData(left)
	right = quickSortByteData(right)
	return append(append(left, mid), right...)
}

// 切分[]ByteData切片，连续的ByteData切分为一个切片
func splitByteData(byteList []ByteData) [][]ByteData {
	var result [][]ByteData
	var temp []ByteData
	for i := 0; i < len(byteList); i++ {
		if len(temp) == 0 {
			temp = append(temp, byteList[i])
			continue
		}
		if byteList[i].StartAddr == byteList[i-1].StartAddr+byteList[i-1].Length {
			temp = append(temp, byteList[i])
		} else {
			// 深拷贝
			result = append(result, append([]ByteData(nil), temp...))
			temp = []ByteData{byteList[i]}
		}
	}
	if len(temp) != 0 {
		result = append(result, append([]ByteData(nil), temp...))
	}
	return result
}

// 组装待发送的[]byte
func assembleSendPayload(byteData []ByteData) ([]byte, error) {
	var byteList []byte
	byteList = append(byteList, 1)                           // 字段号
	byteList = append(byteList, 0)                           // 寄存器编号高字节
	byteList = append(byteList, byte(byteData[0].StartAddr)) // 寄存器编号低字节
	// 先初始化一个寄存器个数，后面再修改
	byteList = append(byteList, 0) // 寄存器个数
	for _, v := range byteData {
		switch v.Value.(type) {
		case float64:
			byteList = append(byteList, byte(v.Value.(float64)))
		case string:
			// 使用|分割
			strList := strings.Split(v.Value.(string), "|")
			for _, str := range strList {
				// 使用strconv.Atoi把字符串转为整数
				num, err := strconv.Atoi(str)
				if err != nil {
					fmt.Println("Error converting string to integer:", err)
					return nil, err
				}
				// 把整数转为字节并加入到byteList中
				byteList = append(byteList, byte(num))
			}
		default:
			return nil, fmt.Errorf("value:%v is invalid", v.Value)
		}
	}
	// 修改寄存器个数
	byteList[3] = byte(len(byteList) - 4)
	return byteList, nil
}
